package fun.ticsmyc.rpc.nacos.registry.impl;

import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import fun.ticsmyc.rpc.common.enumeration.RpcError;
import fun.ticsmyc.rpc.common.exception.RpcException;
import fun.ticsmyc.rpc.nacos.loadbalance.LoadBalancerEnum;
import fun.ticsmyc.rpc.nacos.loadbalance.LoadBalancer;
import fun.ticsmyc.rpc.nacos.loadbalance.NacosLoadBalancers;
import fun.ticsmyc.rpc.nacos.registry.ServiceDiscovery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 服务发现【因为要搭配不同的负载均衡机制，所以是有状态的。 每次使用都new一个】
 * @author Ticsmyc
 * @date 2020-10-30 11:51
 */
public class NacosServiceDiscoveryImpl implements ServiceDiscovery {

    private static final Logger logger = LoggerFactory.getLogger(NacosServiceDiscoveryImpl.class);

    private static NamingService namingService = NacosNameServiceProvider.getInstance();

    private static ConcurrentHashMap<String,List<Instance>> servicePool = new ConcurrentHashMap<>();

    private LoadBalancer loadBalancer;

    public NacosServiceDiscoveryImpl(){
        //默认用轮询作为负载均衡机制
        this(NacosLoadBalancers.getLoadBalancer(LoadBalancerEnum.ROUND_ROBIN));
    }

    public NacosServiceDiscoveryImpl(LoadBalancer loadBalancer){
        this.loadBalancer =loadBalancer;
    }

    /**
     * 从Nacos拉取服务
     * @param serviceName
     * @return
     */
    @Override
    public InetSocketAddress lookupService(String serviceName) {
        Instance instance = null;
        try {
            List<Instance> allInstances = namingService.getAllInstances(serviceName);
            if(allInstances==null || allInstances.size() == 0){
                throw new RpcException(RpcError.SERVICE_NOT_FOUNT,serviceName);
            }
            servicePool.put(serviceName,allInstances);
            instance = loadBalancer.select(allInstances);
            if(instance == null){
                throw new RpcException(RpcError.NO_AVAILABLE_SERVICE,serviceName);
            }
        } catch (NacosException e) {
            e.printStackTrace();
        }
        return new InetSocketAddress(instance.getIp(),instance.getPort());
    }

    /**
     * 先尝试从本地缓存中取， 如果取到的不可用，再从Nacos拉取
     * @param serviceName
     * @param retryTime
     * @return
     */
    @Override
    public InetSocketAddress lookupService(String serviceName, int retryTime) {
        Instance instance = null;
        if(retryTime ==1){
            if(servicePool.containsKey(serviceName)){
                List<Instance> allInstances = servicePool.get(serviceName);
                instance = loadBalancer.select(allInstances);
                if(instance.isEnabled() && instance.isHealthy()){
                    return new InetSocketAddress(instance.getIp(),instance.getPort());
                }else{
                    servicePool.remove(serviceName);
                }
            }
            //本地保存的service不可用，则从Nacos拉取
            return lookupService(serviceName);
        }else{
            //二次以上重试 表示本地缓存大概率过期，直接从Nacos拿
            return lookupService(serviceName);
        }
    }
}
